package com.tongjie.hotelbooking.controller.admin;

import com.tongjie.hotelbooking.authority.entity.Authority;
import com.tongjie.hotelbooking.dto.AdminLoginRequest;
import com.tongjie.hotelbooking.dto.AdminLoginResponse;
import com.tongjie.hotelbooking.dto.LoginResponse;
import com.tongjie.hotelbooking.exception.BusinessException;
import com.tongjie.hotelbooking.http.BaseResponse;
import com.tongjie.hotelbooking.im.websocket.WebSocketEndpoint;
import com.tongjie.hotelbooking.role.entity.Role;
import com.tongjie.hotelbooking.security.SecurityHelper;
import com.tongjie.hotelbooking.security.authentication.AuthenticationService;
import com.tongjie.hotelbooking.security.user.CurrentUserAction;
import com.tongjie.hotelbooking.security.user.CurrentUserInfo;
import com.tongjie.hotelbooking.security.user.CurrentUserPermission;
import com.tongjie.hotelbooking.security.user.CurrentUserRole;
import com.tongjie.hotelbooking.user.entity.User;
import com.tongjie.hotelbooking.user.enums.UserType;
import com.tongjie.hotelbooking.user.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/admin/login")
public class AdminLoginController {

    @Resource
    private UserService userService;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private AuthenticationService authenticationService;

    @PostMapping("/login")
    public AdminLoginResponse login(@RequestBody AdminLoginRequest adminLoginRequest) {
        User user = this.userService.getUserByUsername(adminLoginRequest.getUsername());
        if (user == null) {
            throw new BusinessException(6000, "用户不存在");
        }

        if (!UserType.ADMIN.equals(user.getUserType())) {
            throw new BusinessException(6001, "该用户不是管理员");
        }

        if (!passwordEncoder.matches(adminLoginRequest.getPassword(), user.getPassword())) {
            throw new BusinessException(6002, "密码错误");
        }

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();


        CurrentUserInfo currentUserInfo = new CurrentUserInfo();
        currentUserInfo.setId(user.getId());
        currentUserInfo.setName(user.getNickName());
        currentUserInfo.setUsername(user.getUsername());
        currentUserInfo.setPassword(user.getPassword());
        currentUserInfo.setAvatar(user.getAvatar());
        currentUserInfo.setTelephone(user.getMobile());
        currentUserInfo.setLastLoginIp(user.getLastLoginIp());
        currentUserInfo.setLastLoginTime(Optional.ofNullable(user.getLastLoginTime()).map(Date::getTime).orElse(0L));
        currentUserInfo.setCreatorId("");
        currentUserInfo.setCreateTime(Optional.ofNullable(user.getLastLoginTime()).map(Date::getTime).orElse(0L));
        currentUserInfo.setDeleted(0);
        currentUserInfo.setRoleId("admin");
        currentUserInfo.setMobile(user.getMobile());
        currentUserInfo.setWxOpenId(user.getWxOpenId());
        currentUserInfo.setUserType(user.getUserType());

        currentUserInfo.setRole(this.buildCurrentUserRole(user));
        Authentication authentication = this.authenticationService.authenticate(request, response, currentUserInfo);
        if (authentication == null) {
            throw new BusinessException(6003, "login failed");
        }

        return AdminLoginResponse.builder()
                .token(request.getSession().getId())
                .userType(user.getUserType())
                .currentUserInfo(currentUserInfo).build();
    }

    private CurrentUserRole buildCurrentUserRole(User user) {
        if (CollectionUtils.isEmpty(user.getRoles())) {
            return null;
        }

        Role role = user.getRoles().get(0);
        CurrentUserRole currentUserRole = new CurrentUserRole();
        currentUserRole.setId(role.getId().toString());
        currentUserRole.setName(role.getRoleName());
        currentUserRole.setDescribe(role.getDescription());
        currentUserRole.setStatus(1);
        currentUserRole.setCreatorId("system");
        currentUserRole.setCreateTime(0L);
        currentUserRole.setDeleted(0);

        currentUserRole.setPermissions(this.buildCurrentUserPermission(role));

        return currentUserRole;
    }

    private List<CurrentUserPermission> buildCurrentUserPermission(Role role) {
        List<CurrentUserPermission> currentUserPermissions = new ArrayList<>();
        for (Authority authority : role.getAuthorities()) {
            if (!StringUtils.contains(authority.getAuthorityCode(), "_")) {
                CurrentUserPermission currentUserPermission = new CurrentUserPermission();
                currentUserPermission.setRoleId(authority.getId().toString());
                currentUserPermission.setPermissionId(authority.getAuthorityCode());
                currentUserPermission.setPermissionName(authority.getAuthorityName());
                currentUserPermissions.add(currentUserPermission);
            }
        }

        for (CurrentUserPermission currentUserPermission : currentUserPermissions) {
            for (Authority authority : role.getAuthorities()) {
                if (StringUtils.startsWith(authority.getAuthorityCode(), currentUserPermission.getPermissionId() + "_")) {
                    CurrentUserAction currentUserAction = new CurrentUserAction();
                    currentUserAction.setAction(authority.getAuthorityCode());
                    currentUserAction.setDescribe(authority.getDescription());
                    currentUserAction.setDefaultCheck(false);
                    currentUserPermission.getActionEntitySet().add(currentUserAction);
                }
            }
        }
        return currentUserPermissions;
    }

    @GetMapping("/current")
    public CurrentUserInfo getCurrent() {
        return SecurityHelper.getCurrentUserInfo();
    }

    @PostMapping("/logout")
    public void logout(CurrentUserInfo user) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        WebSocketEndpoint.closeConnection(user.getId());
        request.getSession().invalidate();
    }


}
